package game;

import misc.Vector3i;
import board.Tile;
import action.MoveAction;
import action.AttackAction;
import action.Action;
import character.Character;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.FastMath;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import java.util.List;

public class TurnInputHandler implements ActionListener, AnalogListener {

    public TurnInputHandler() {
        DataStore.inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
	DataStore.inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
	DataStore.inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
	DataStore.inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
        DataStore.inputManager.addMapping("Move", new KeyTrigger(KeyInput.KEY_E));
        DataStore.inputManager.addMapping("CancelMove", new KeyTrigger(KeyInput.KEY_X));
        DataStore.inputManager.addMapping("EndTurn", new KeyTrigger(KeyInput.KEY_RETURN));

	DataStore.inputManager.addMapping("Select", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
	DataStore.inputManager.addMapping("Action", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
    }
    
    public void register() {
        DataStore.inputManager.addListener(this, "Left", "Right", "Up", "Down", "Move", "CancelMove", "EndTurn", "Select", "Action");
    }
    
    public void onAnalog(String name, float value, float tpf) {
        //override cam controls
	if(name.equals("Left")) {
	    
	} else if(name.equals("Right")) {
	    
	} else if(name.equals("Up")) {
	    
	} else if(name.equals("Down")) {
	    
	}
    }

    public void onAction(String name, boolean isPressed, float tpf) {
        if(isPressed) {
	    if(name.equals("Select")) {
		doMouseSelect();
	    } else if(name.equals("Action")) {
		doMouseAction();
	    } else if(name.equals("Move")) {
                if(TurnController.getCurrentHumanPlayer().hasSelectedCharacter()) {
		    Character selectedCharacter = TurnController.getCurrentHumanPlayer().getSelectedCharacter();
                    List<Vector3i> validMoveLocations = selectedCharacter.getValidMoveLocations();
		    Action moveAction = new MoveAction(selectedCharacter, validMoveLocations.get(FastMath.rand.nextInt(validMoveLocations.size())));
		    if(checkEnoughTicks(selectedCharacter, moveAction)) {
			selectedCharacter.getActionQueue().queueActionLast(moveAction);
		    }
		}
            } else if(name.equals("CancelMove")) {
                if(TurnController.getCurrentHumanPlayer().hasSelectedCharacter()) {
                    TurnController.getCurrentHumanPlayer().getSelectedCharacter().getActionQueue().clearAllActions();
                    System.out.println("all actions cleared");
                }
	    } else if(name.equals("EndTurn")) {
                TurnController.endCurrentTurn();
            }
        }
    }

    public void doMouseSelect() {
	deselectAll();
	CollisionResult target = rayCastFromMouseFirstCollision(DataStore.rootNode);
        if(target != null) {
            if(target.getGeometry() instanceof Character) { //rework this line when character is no longer a geometry
		if(((Character)target.getGeometry()).getPlayer().equals(TurnController.getCurrentHumanPlayer())) {
		    TurnController.getCurrentHumanPlayer().setSelectedCharacter((Character)target.getGeometry());
		    System.out.println("selected: "+TurnController.getCurrentHumanPlayer().getSelectedCharacter());
		}
	    }
        }
    }

    public void doMouseAction() {
	CollisionResult target = rayCastFromMouseFirstCollision(DataStore.rootNode);
        if(target != null) {
            if(TurnController.getCurrentHumanPlayer().hasSelectedCharacter()) {
                Character selectedCharacter = TurnController.getCurrentHumanPlayer().getSelectedCharacter();
		if(target.getGeometry().getParent() instanceof Tile) {
		    Tile targetTile = (Tile)target.getGeometry().getParent();
		    if(selectedCharacter.getValidMoveLocations().contains(targetTile.getBoardLocation())) {
			Action moveAction = new MoveAction(selectedCharacter, targetTile.getBoardLocation());
			if(checkEnoughTicks(selectedCharacter, moveAction)) {
			    selectedCharacter.getActionQueue().queueActionLast(moveAction);
			    System.out.println("location set");
			}

		    } else {
                        System.out.println("Not a valid move location!");
                    }
		} else if(target.getGeometry() instanceof Character) { //rework this line when character is no longer a geometry
		    Character targetChar = (Character)target.getGeometry();
                    if(!targetChar.getPlayer().equals(TurnController.getCurrentHumanPlayer())) {
			if(CombatUtil.checkAttackRange(selectedCharacter, targetChar)) {
			    Action attackAction = new AttackAction(selectedCharacter, targetChar);
			    if(checkEnoughTicks(selectedCharacter, attackAction)) {
				selectedCharacter.getActionQueue().queueActionLast(attackAction);
				System.out.println("queueing up attack");
			    }
			} else {
			    System.out.println("Out of range.");
			}
                    }
                }
            }
        }
    }

    public boolean checkEnoughTicks(Character character, Action action) {
	boolean enoughTicks = character.getActionQueue().getTicksQueued()+action.getTotalTicks() <= ResolutionController.TICKS_PER_RESOLUTION;
	if(!enoughTicks)
	    System.out.println("Character does not have enough ticks remaining to perform that action.");
	return enoughTicks;
    }

    public void deselectAll() {
	TurnController.getCurrentHumanPlayer().clearSelectedCharacter();
    }

    public CollisionResult rayCastFromMouseFirstCollision(Node onNode) {
        CollisionResults results = new CollisionResults();
	Vector2f click2d = DataStore.inputManager.getCursorPosition();
	Vector3f click3d = TurnController.getCurrentHumanPlayer().getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
	Vector3f dir = TurnController.getCurrentHumanPlayer().getCamera().getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
	Ray ray = new Ray(click3d, dir);
        onNode.collideWith(ray, results);
        if (results.size() > 0) {
	  CollisionResult closest = results.getClosestCollision();
          return closest;
        }
        return null;
    }
}
